<!doctype html>
<html lang="zh-CN">
<head><meta name="generator" content="Hexo 3.8.0">
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=11,IE=10,IE=9,IE=8">
    <meta name="baidu-site-verification" content="dIcXMeY8Ya">
    
    <title>用户态使用 glibc/backtrace 追踪函数调用堆栈定位段错误 | OSKernelLAB</title>
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">
    <meta name="keywords" content="gatieme, 成坚, 内核, linux, kernel">
    <meta name="description" content="内核杂谈">

    
    <link rel="alternative" href="/atom.xml" title="OSKernelLAB" type="application/atom+xml">
    
    
    <link rel="icon" href="/favicon.ico">
    
    <link rel="stylesheet" href="/css/style.css?v=1615735433171">
    <!--[if lt IE 9]>
    <script src="/js/html5.js"></script>
    <![endif]-->
    
<script>
    var _hmt = _hmt || [];
    (function() {
        var hm = document.createElement("script");
        hm.src="https://hm.baidu.com/hm.js?1a8f9a67050c5fdb4c73cbbc00124bd8"
        var s = document.getElementsByTagName("script")[0];
        s.parentNode.insertBefore(hm, s);
    })();
</script>


</head>
</html>
<body class="home">
    <!--[if lt IE 9]>
    <div class="browsehappy">
        当前网页 <strong>不支持</strong>
        你正在使用的浏览器. 为了正常的访问, 请 <a href="http://browsehappy.com/">升级你的浏览器</a>.
    </div>
    <![endif]-->

    <!-- 博客头部 -->
    <header class="header">
    <section class="container header-main">
        <div class="logo">
            <a href="/">
                <div class="cover">
                    <span class="name">OSKernelLAB</span>
                    <span class="description">OS内核实验室</span>
                </div>
            </a>
        </div>
        <div class="dropnav iconfont icon-nav" id="JELON__btnDropNav"></div>
        <ul class="menu hidden" id="JELON__menu">
            
            <li rel="/2018/11/17/2018/1117-0001-use_glibc_backtrace_to_report_active_stack_frames_userspace/index.html" class="item ">
                <a href="/" title="首页" class="iconfont icon-home">&nbsp;首页</a>
            </li>
            
            <li rel="/2018/11/17/2018/1117-0001-use_glibc_backtrace_to_report_active_stack_frames_userspace/index.html" class="item ">
                <a href="/archives/" title="归档" class="iconfont icon-archives">&nbsp;归档</a>
            </li>
            
            <li rel="/2018/11/17/2018/1117-0001-use_glibc_backtrace_to_report_active_stack_frames_userspace/index.html" class="item ">
                <a href="/lab/" title="实验室" class="iconfont icon-archives">&nbsp;实验室</a>
            </li>
            
            <li rel="/2018/11/17/2018/1117-0001-use_glibc_backtrace_to_report_active_stack_frames_userspace/index.html" class="item ">
                <a href="/navigation/" title="网址导航" class="iconfont icon-archives">&nbsp;网址导航</a>
            </li>
            
            <li rel="/2018/11/17/2018/1117-0001-use_glibc_backtrace_to_report_active_stack_frames_userspace/index.html" class="item ">
                <a href="/about/" title="关于" class="iconfont icon-staff">&nbsp;关于</a>
            </li>
            
            <li rel="/2018/11/17/2018/1117-0001-use_glibc_backtrace_to_report_active_stack_frames_userspace/index.html" class="item ">
                <a href="/comment/" title="留言" class="iconfont icon-comment">&nbsp;留言</a>
            </li>
            
        </ul>
        <div class="profile clearfix">
            <div class="feeds fl">
                
                
                <p class="links">
                    
                        <a href="https://github.com/gatieme" target="_blank">Github</a>
                        |
                    
                        <a href="https://github.com/gatieme/gatieme.github.io" target="_blank">Hosted by Github Pages</a>
                        
                    
                </p>
                <p class="sns">
                    
                        <a href="https://blog.csdn.net/gatieme" class="csdn" target="_blank"><b>■</b> CSDN 博客</a>
                    
                        <a href="https://www.facebook.com/gatieme" class="qqweibo" target="_blank"><b>■</b> Facebook</a>
                    
                    <a href="javascript: void(0);" class="wechat">
                        <b>■</b>
                        公众号
                        <span class="popover">
                            <img src="/img/wechat_mp.jpg" width="120" height="120" alt="我的微信订阅号">
                            <i class="arrow"></i>
                        </span>
                    </a>
                </p>
                
            </div>
            <div class="avatar fr">
                <img src="/img/gatieme.jpg" alt="avatar" title="Gatieme-(成坚)">
            </div>
        </div>
    </section>
</header>


    <!-- 博客正文 -->
    <div class="container body clearfix">
        <section class="content">
            <div class="content-main widget">
                <!-- 文章页 -->
<!-- 文章 -->
<article class="post article">
    <header class="text-center">
        <h3 class="post-title"><span>用户态使用 glibc/backtrace 追踪函数调用堆栈定位段错误</span></h3>
    </header>
    <p class="post-meta text-center">
        gatieme 发表于
        <time datetime="2018-11-17T07:22:00.000Z">2018-11-17</time>
    </p>
    <div id="JELON__articlePostContent" class="post-content">
        <table>
<thead>
<tr>
<th style="text-align:center">CSDN</th>
<th style="text-align:center">GitHub</th>
<th style="text-align:center">Hexo</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center"><a href="https://blog.csdn.net/gatieme/article/details/84189280" target="_blank" rel="noopener">用户态使用 glibc/backtrace 追踪函数调用堆栈定位段错误</a></td>
<td style="text-align:center"><a href="https://github.com/gatieme/AderXCoding/tree/master/language/c/backtrace" target="_blank" rel="noopener"><code>AderXCoding/language/c/backtrace</code></a></td>
<td style="text-align:center"><a href="https://gatieme.github.io/2018/11/17/2018/1117-0001-0001-use_glibc_backtrace_to_report_active_stack_frames_userspace" target="_blank" rel="noopener">KernelShow(gatieme.github.io)</a></td>
</tr>
</tbody>
</table>
<p><br></p>
<p><a rel="noopener" href="http://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank"><img alt="知识共享许可协议" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png"></a></p>
<p>本作品采用<a rel="noopener" href="http://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议</a>进行许可, 转载请注明出处, 谢谢合作</p>
<p>因本人技术水平和知识面有限, 内容如有纰漏或者需要修正的地方, 欢迎大家指正, 也欢迎大家提供一些其他好的调试工具以供收录, 鄙人在此谢谢啦</p>
<p><br></p>
<p>一般察看函数运行时堆栈的方法是使用 <code>GDB(bt命令)</code> 之类的外部调试器, 但是, 有些时候为了分析程序的 <code>BUG</code>,(主要针对长时间运行程序的分析),在程序出错时打印出函数的调用堆栈是非常有用的.</p>
<h2 id="1-glibc-获取堆栈信息的接口"><a href="#1-glibc-获取堆栈信息的接口" class="headerlink" title="#1    glibc 获取堆栈信息的接口"></a>#1    glibc 获取堆栈信息的接口</h2><p>在 <code>glibc</code> 头文件 <code>execinfo.h</code> 中声明了三个函数用于获取当前线程的函数调用堆栈.</p>
<h2 id="1-1"><a href="#1-1" class="headerlink" title="#1.1"></a>#1.1</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;execinfo.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* Store up to SIZE return address of the current program state in</span></span><br><span class="line"><span class="comment">   ARRAY and return the exact number of values stored.  */</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">backtrace</span><span class="params">(<span class="keyword">void</span> **<span class="built_in">array</span>, <span class="keyword">int</span> size)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* Return names of functions from the backtrace list in ARRAY in a newly</span></span><br><span class="line"><span class="comment">   malloc()ed memory block.  */</span></span><br><span class="line"><span class="function"><span class="keyword">char</span> **<span class="title">backtrace_symbols</span><span class="params">(<span class="keyword">void</span> *<span class="keyword">const</span> *<span class="built_in">array</span>, <span class="keyword">int</span> size)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* This function is similar to backtrace_symbols() but it writes the</span></span><br><span class="line"><span class="comment">   result immediately to a file.  */</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">backtrace_symbols_fd</span><span class="params">(<span class="keyword">void</span> *<span class="keyword">const</span> *<span class="built_in">array</span>, <span class="keyword">int</span> size, <span class="keyword">int</span> fd)</span></span>;</span><br></pre></td></tr></table></figure>
<p>使用它们的时候有一下几点需要我们注意的地方：</p>
<ul>
<li><p>backtrace的实现依赖于栈指针(fp寄存器), 在gcc编译过程中任何非零的优化等级（-On参数）或加入了栈指针优化参数 <code>-fomit-frame-pointer</code> 后多将不能正确得到程序栈信息;</p>
</li>
<li><p>backtrace_symbols的实现需要符号名称的支持, 在gcc编译过程中需要加入 <code>-rdynamic</code> 参数</p>
</li>
<li><p>内联函数没有栈帧, 它在编译过程中被展开在调用的位置；</p>
</li>
<li><p>尾调用优化(Tail-call Optimization)将复用当前函数栈, 而不再生成新的函数栈, 这将导致栈信息不能正确被获取。</p>
</li>
</ul>
<h2 id="1-2-backtrace"><a href="#1-2-backtrace" class="headerlink" title="##1.2    backtrace"></a>##1.2    backtrace</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">backtrace</span><span class="params">(<span class="keyword">void</span> **buffer,<span class="keyword">int</span> size)</span></span></span><br></pre></td></tr></table></figure>
<p>该函数用于获取当前线程的调用堆栈,</p>
<p>参数:<br>    获取的信息将会被存放在 <code>buffer</code> 中,它是一个指针列表.<br>    参数 <code>size</code> 用来指定 <code>buffer</code> 中可以保存多少个 <code>void*</code> 元素.</p>
<p>函数返回值:<br>    实际获取的指针个数, 最大不超过 <code>size</code>大小.</p>
<p>在 <code>buffer</code> 中的指针实际是从堆栈中获取的返回地址, 每一个堆栈框架有一个返回地址</p>
<p>注意:某些编译器的优化选项对获取正确的调用堆栈有干扰,另外内联函数没有堆栈框架;删除框架指针也会导致无法正确解析堆栈内容</p>
<h2 id="1-3-backtrace-symbols"><a href="#1-3-backtrace-symbols" class="headerlink" title="##1.3    backtrace_symbols"></a>##1.3    backtrace_symbols</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">char</span> ** <span class="title">backtrace_symbols</span> <span class="params">(<span class="keyword">void</span> *<span class="keyword">const</span> *buffer, <span class="keyword">int</span> size)</span></span></span><br></pre></td></tr></table></figure>
<p><code>backtrace_symbols</code> 将从 <code>backtrace</code> 函数获取的信息转化为一个字符串数组.</p>
<p>参数:<br>    <code>buffer</code> 应该是从 <code>backtrace</code> 函数获取的指针数组<br>    <code>size</code> 是该数组中的元素个数(<code>backtrace</code> 的返回值)</p>
<p>函数返回值:<br>    一个指向字符串数组的指针, 它的大小同 <code>buffer</code> 相同.<br>    每个字符串包含了一个相对于buffer中对应元素的可打印信息.<br>    它包括函数名，函数的偏移地址,和实际的返回地址</p>
<p>现在, 只有使用ELF二进制格式的程序才能获取函数名称和偏移地址. 在其他系统,只有16进制的返回地址能被获取.<br>另外,你可能需要传递相应的符号给链接器,以能支持函数名功能</p>
<blockquote>
<p>(比如,在使用GNU ld链接器的系统中,你需要传递(-rdynamic)， -rdynamic可用来通知链接器将所有符号添加到动态符号表中，如果你的链接器支持-rdynamic的话，建议将其加上！)</p>
</blockquote>
<p>该函数的返回值是通过malloc函数申请的空间,因此调用者必须使用free函数来释放指针.</p>
<blockquote>
<p>注意 : 如果不能为字符串获取足够的空间函数的返回值将会为NULL</p>
</blockquote>
<h2 id="1-4-backtrace-symbols-fd"><a href="#1-4-backtrace-symbols-fd" class="headerlink" title="##1.4    backtrace_symbols_fd"></a>##1.4    backtrace_symbols_fd</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">backtrace_symbols_fd</span> <span class="params">(<span class="keyword">void</span> *<span class="keyword">const</span> *buffer, <span class="keyword">int</span> size, <span class="keyword">int</span> fd)</span></span></span><br></pre></td></tr></table></figure>
<p><code>backtrace_symbols_fd</code> 与 <code>backtrace_symbols</code> 函数具有相同的功能, 不同的是它不会给调用者返回字符串数组,而是将结果写入文件描述符为 <code>fd</code> 的文件中, 每个函数对应一行.它不需要调用malloc函数,因此适用于有可能调用该函数会失败的情况</p>
<h2 id="2-示例"><a href="#2-示例" class="headerlink" title="#2    示例"></a>#2    示例</h2><h2 id="2-1-简单用例-glibc-提供"><a href="#2-1-简单用例-glibc-提供" class="headerlink" title="##2.1    简单用例(glibc 提供)"></a>##2.1    简单用例(glibc 提供)</h2><p>下面是 <code>glibc</code> 中的实例：</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// http://www.gnu.org/software/libc/manual/html_node/Backtraces.html</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;execinfo.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* Obtain a backtrace and print it to @code&#123;stdout&#125;. */</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">print_trace</span> <span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	<span class="keyword">void</span>    * <span class="built_in">array</span>[<span class="number">10</span>];</span><br><span class="line">	<span class="keyword">size_t</span>  size;</span><br><span class="line">	<span class="keyword">char</span>    ** strings;</span><br><span class="line">	<span class="keyword">size_t</span>  i;</span><br><span class="line"></span><br><span class="line">	size = backtrace(<span class="built_in">array</span>, <span class="number">10</span>);</span><br><span class="line">	strings = backtrace_symbols (<span class="built_in">array</span>, size);</span><br><span class="line">	<span class="keyword">if</span> (<span class="literal">NULL</span> == strings)</span><br><span class="line">	&#123;</span><br><span class="line">		perror(<span class="string">"backtrace_symbols"</span>);</span><br><span class="line">		<span class="built_in">exit</span>(EXIT_FAILURE);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="built_in">printf</span> (<span class="string">"Obtained %zd stack frames.\n"</span>, size);</span><br><span class="line"></span><br><span class="line">	<span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; size; i++)</span><br><span class="line">		<span class="built_in">printf</span> (<span class="string">"%s\n"</span>, strings[i]);</span><br><span class="line"></span><br><span class="line">	<span class="built_in">free</span> (strings);</span><br><span class="line">	strings = <span class="literal">NULL</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* A dummy function to make the backtrace more interesting. */</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">dummy_function</span> <span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	print_trace();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span> <span class="params">(<span class="keyword">int</span> argc, <span class="keyword">char</span> *argv[])</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	dummy_function();</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>输出如下：</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">gcc -c example.c -o example.o    -rdynamic -g</span><br><span class="line">gcc example.o -o example  -rdynamic -g</span><br><span class="line"></span><br><span class="line">#./example</span><br><span class="line"></span><br><span class="line">Obtained <span class="number">5</span> <span class="built_in">stack</span> frames.</span><br><span class="line">./example(print_trace+<span class="number">0x19</span>) [<span class="number">0x400916</span>]</span><br><span class="line">./example(dummy_function+<span class="number">0x9</span>) [<span class="number">0x4009bb</span>]</span><br><span class="line">./example(main+<span class="number">0x14</span>) [<span class="number">0x4009d1</span>]</span><br><span class="line">/lib64/libc.so<span class="number">.6</span>(__libc_start_main+<span class="number">0xf5</span>) [<span class="number">0x7fb5e7f49445</span>]</span><br><span class="line">./example() [<span class="number">0x400839</span>]</span><br></pre></td></tr></table></figure>
<p><img src="https://raw.githubusercontent.com/gatieme/AderXCoding/master/language/c/backtrace/example.png" alt="example"></p>
<h2 id="2-2-简单使用-man手册"><a href="#2-2-简单使用-man手册" class="headerlink" title="##2.2    简单使用(man手册)"></a>##2.2    简单使用(man手册)</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//http://man7.org/linux/man-pages/man3/backtrace.3.html</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;execinfo.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line">	<span class="keyword">void</span></span><br><span class="line">myfunc3(<span class="keyword">void</span>)</span><br><span class="line">&#123;</span><br><span class="line">	<span class="keyword">int</span> j, nptrs;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SIZE 100</span></span><br><span class="line">	<span class="keyword">void</span> *buffer[<span class="number">100</span>];</span><br><span class="line">	<span class="keyword">char</span> **strings;</span><br><span class="line"></span><br><span class="line">	nptrs = backtrace(buffer, SIZE);</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">"backtrace() returned %d addresses\n"</span>, nptrs);</span><br><span class="line"></span><br><span class="line">	<span class="comment">/* The call backtrace_symbols_fd(buffer, nptrs,</span></span><br><span class="line"><span class="comment">	 * STDOUT_FILENO)</span></span><br><span class="line"><span class="comment">	 *               would produce similar output to the</span></span><br><span class="line"><span class="comment">	 *               following: */</span></span><br><span class="line"></span><br><span class="line">	strings = backtrace_symbols(buffer, nptrs);</span><br><span class="line">	<span class="keyword">if</span> (strings == <span class="literal">NULL</span>) &#123;</span><br><span class="line">		perror(<span class="string">"backtrace_symbols"</span>);</span><br><span class="line">		<span class="built_in">exit</span>(EXIT_FAILURE);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">for</span> (j = <span class="number">0</span>; j &lt; nptrs; j++)</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">"%s\n"</span>, strings[j]);</span><br><span class="line"></span><br><span class="line">	<span class="built_in">free</span>(strings);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">void</span>   <span class="comment">/* "static" means don't export the symbol... */</span></span><br><span class="line">myfunc2(<span class="keyword">void</span>)</span><br><span class="line">&#123;</span><br><span class="line">	myfunc3();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">void</span></span><br><span class="line">myfunc(<span class="keyword">int</span> ncalls)</span><br><span class="line">&#123;</span><br><span class="line">	<span class="keyword">if</span> (ncalls &gt; <span class="number">1</span>)</span><br><span class="line">		myfunc(ncalls - <span class="number">1</span>);</span><br><span class="line">	<span class="keyword">else</span></span><br><span class="line">		myfunc2();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>编译运行程序</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">gcc -c prog.c -o prog.o    -rdynamic -g</span><br><span class="line">gcc prog.o -o prog  -rdynamic -g</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">#./prog <span class="number">3</span></span><br><span class="line"></span><br><span class="line">backtrace() returned <span class="number">8</span> addresses</span><br><span class="line">./prog(myfunc3+<span class="number">0x1f</span>) [<span class="number">0x4009cc</span>]</span><br><span class="line">./prog() [<span class="number">0x400a61</span>]</span><br><span class="line">./prog(myfunc+<span class="number">0x25</span>) [<span class="number">0x400a88</span>]</span><br><span class="line">./prog(myfunc+<span class="number">0x1e</span>) [<span class="number">0x400a81</span>]</span><br><span class="line">./prog(myfunc+<span class="number">0x1e</span>) [<span class="number">0x400a81</span>]</span><br><span class="line">./prog(main+<span class="number">0x59</span>) [<span class="number">0x400ae3</span>]</span><br><span class="line">/lib64/libc.so<span class="number">.6</span>(__libc_start_main+<span class="number">0xf5</span>) [<span class="number">0x7f1d1b1f1445</span>]</span><br><span class="line">./prog() [<span class="number">0x4008e9</span>]</span><br></pre></td></tr></table></figure>
<p><img src="https://raw.githubusercontent.com/gatieme/AderXCoding/master/language/c/backtrace/prog.png" alt="prog"></p>
<h2 id="2-3-段错误时自动触发-call-trace"><a href="#2-3-段错误时自动触发-call-trace" class="headerlink" title="##2.3    段错误时自动触发 call trace"></a>##2.3    段错误时自动触发 <code>call trace</code></h2><p>我们还可以利用这 <code>backtrace</code> 来定位段错误位置.</p>
<p>通常情况系, 程序发生段错误时系统会发送 <code>SIGSEGV</code> 信号给程序, 缺省处理是退出函数.</p>
<p>我们可以使用 <code>signal(SIGSEGV, &amp;your_function);</code> 函数来接管 <code>SIGSEGV</code> 信号的处理,<br>程序在发生段错误后, 自动调用我们准备好的函数, 从而在那个函数里来获取当前函数调用栈.</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stddef.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;execinfo.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;signal.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* Obtain a backtrace and print it to stdout. */</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">dump_stack</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	<span class="keyword">void</span> *<span class="built_in">array</span>[<span class="number">30</span>] = &#123; <span class="number">0</span> &#125;;</span><br><span class="line">	<span class="keyword">size_t</span> size = backtrace(<span class="built_in">array</span>, ARRAY_SIZE(<span class="built_in">array</span>));</span><br><span class="line">	<span class="keyword">char</span> **strings = backtrace_symbols(<span class="built_in">array</span>, size);</span><br><span class="line">	<span class="keyword">size_t</span> i;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">if</span> (strings == <span class="literal">NULL</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		perror(<span class="string">"backtrace_symbols."</span>);</span><br><span class="line">		<span class="built_in">exit</span>(EXIT_FAILURE);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">"Obtained %zd stack frames.\n"</span>, size);</span><br><span class="line"></span><br><span class="line">	<span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; size; i++)</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">"%s\n"</span>, strings[i]);</span><br><span class="line"></span><br><span class="line">	<span class="built_in">free</span>(strings);</span><br><span class="line">	strings = <span class="literal">NULL</span>;</span><br><span class="line"></span><br><span class="line">	<span class="built_in">exit</span>(EXIT_SUCCESS);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">sighandler_dump_stack</span><span class="params">(<span class="keyword">int</span> sig)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	psignal(sig, <span class="string">"handler"</span>);</span><br><span class="line">	dump_stack();</span><br><span class="line">	signal(sig, SIG_DFL);</span><br><span class="line">	raise(sig);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">func_c</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	*((<span class="keyword">volatile</span> <span class="keyword">int</span> *)<span class="number">0x0</span>) = <span class="number">0x9999</span>; <span class="comment">/* ERROR */</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">func_b</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	func_c();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">func_a</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	func_b();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">const</span> <span class="keyword">char</span> *argv[])</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	<span class="keyword">if</span> (signal(SIGSEGV, sighandler_dump_stack) == SIG_ERR)</span><br><span class="line">		perror(<span class="string">"can't catch SIGSEGV"</span>);</span><br><span class="line"></span><br><span class="line">	func_a();</span><br><span class="line"></span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>编译该程序</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">cc -c handler.c -o handler.o    -rdynamic</span><br><span class="line">cc handler.o -o handler  -rdynamic</span><br></pre></td></tr></table></figure>
<p>接着运行.</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">#./handler</span><br><span class="line"></span><br><span class="line">handler: Segmentation fault</span><br><span class="line">Obtained <span class="number">9</span> <span class="built_in">stack</span> frames.</span><br><span class="line">./handler(dump_stack+<span class="number">0x39</span>) [<span class="number">0x400aa6</span>]</span><br><span class="line">./handler(sighandler_dump_stack+<span class="number">0x1f</span>) [<span class="number">0x400b6c</span>]</span><br><span class="line">/lib64/libc.so<span class="number">.6</span>(+<span class="number">0x362f0</span>) [<span class="number">0x7f0bc00f72f0</span>]</span><br><span class="line">./handler(func_c+<span class="number">0x9</span>) [<span class="number">0x400b90</span>]</span><br><span class="line">./handler(func_b+<span class="number">0xe</span>) [<span class="number">0x400ba6</span>]</span><br><span class="line">./handler(func_a+<span class="number">0xe</span>) [<span class="number">0x400bb6</span>]</span><br><span class="line">./handler(main+<span class="number">0x38</span>) [<span class="number">0x400bf0</span>]</span><br><span class="line">/lib64/libc.so<span class="number">.6</span>(__libc_start_main+<span class="number">0xf5</span>) [<span class="number">0x7f0bc00e3445</span>]</span><br><span class="line">./handler() [<span class="number">0x4009a9</span>]</span><br></pre></td></tr></table></figure>
<p><img src="https://raw.githubusercontent.com/gatieme/AderXCoding/master/language/c/backtrace/handler.png" alt="程度异常后自动打印调用栈"></p>
<p>可以看出, 真正出异常的函数位置在 <code>./handler(func_c+0x9) [0x400b90]</code>.</p>
<p>我们可以看下这个位置位于哪里:</p>
<ul>
<li>使用 <code>addr2line</code></li>
</ul>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">addr2line -C -f -e  ./handler <span class="number">0x400b90</span></span><br></pre></td></tr></table></figure>
<p><img src="https://raw.githubusercontent.com/gatieme/AderXCoding/master/language/c/backtrace/addr2line.png" alt="addr2line 将行号显示出来"></p>
<p>对应错误的行号.</p>
<p><img src="https://raw.githubusercontent.com/gatieme/AderXCoding/master/language/c/backtrace/bugline.png" alt="bugline"></p>
<ul>
<li>使用 <code>objdump</code></li>
</ul>
<p>使用 objdump 将函数的指令信息 dump 出来.<br>其中  -D 参数表示显示所有汇编代码, -S 表示将对应的源码也显示出来<br>最后用 grep 显示地址 0x400b90 处前后 6 行的信息</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">objdump -DS ./handler | grep <span class="number">-6</span>  <span class="string">"400b90"</span></span><br></pre></td></tr></table></figure>
<p><img src="https://raw.githubusercontent.com/gatieme/AderXCoding/master/language/c/backtrace/objdump.png" alt="objdump 将异常欣喜 dump 出来"></p>
<p>参考代码:</p>
<blockquote>
<p><a href="https://github.com/castoz/backtrace" target="_blank" rel="noopener">a user-space simulated dump_stack(), based on mips.</a></p>
<p><a href="https://elixir.bootlin.com/linux/v4.19.2/source/tools/perf/util/debug.c#L260" target="_blank" rel="noopener">kernel perf source dump_stack</a></p>
</blockquote>
<h2 id="3-更低层次的函数"><a href="#3-更低层次的函数" class="headerlink" title="#3    更低层次的函数"></a>#3    更低层次的函数</h2><p>只有使用 <code>glibc 2.1</code> 或更新版本, 可以使用 <code>backtrace()</code> 函数, 参看 <code>&lt;execinfo.h&gt;</code>, 并且不同架构和系统中可能有不同的支持.</p>
<p>因此 <code>GCC</code> 提供了两个内置函数用来在运行时取得函数调用栈中的返回地址和框架地址</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">void</span> *__builtin_return_address(<span class="keyword">int</span> level);</span><br></pre></td></tr></table></figure>
<p>得到当前函数层次为 level 的返回地址， 即此函数被别的函数调用, 然后此函数执行完毕后, 返回, 所谓返回地址就是调用的时候的地址(其实是调用位置的下一条指令的地址).</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">void</span>* __builtin_frame_address (<span class="keyword">unsigned</span> <span class="keyword">int</span> level);</span><br></pre></td></tr></table></figure>
<p>得到当前函数的栈帧的地址.</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;memory.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;signal.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;ucontext.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;dlfcn.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;execinfo.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">showBacktrace</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">        <span class="keyword">void</span> * ret = __builtin_return_address(<span class="number">1</span>);</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"ret address [%p]\n"</span>, ret);</span><br><span class="line">        <span class="keyword">void</span> * caller = __builtin_frame_address(<span class="number">0</span>);</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"call address [%p]\n"</span>, caller);</span><br><span class="line"><span class="meta">#<span class="meta-keyword">ifdef</span> __cplusplus</span></span><br><span class="line">        Dl_info dlinfo;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">void</span> *ip = ret;</span><br><span class="line">        <span class="keyword">if</span>(!dladdr(ip, &amp;dlinfo)) &#123;</span><br><span class="line">                perror(<span class="string">"addr not found\n"</span>);</span><br><span class="line">                <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">const</span> <span class="keyword">char</span> *symname = dlinfo.dli_sname;</span><br><span class="line">        <span class="keyword">int</span> f = <span class="number">0</span>;</span><br><span class="line">        <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">"% 2d: %p %s+%u (%s)\n"</span>,</span><br><span class="line">                        ++f,</span><br><span class="line">                        ip,</span><br><span class="line">                        symname, <span class="number">0</span>,</span><br><span class="line"><span class="comment">// (unsigned)(ip - dlinfo.dli_saddr),</span></span><br><span class="line"></span><br><span class="line">                        dlinfo.dli_fname);</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">MyFunc_A</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">        showBacktrace();</span><br><span class="line">        <span class="keyword">return</span> <span class="number">10</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">MyFunc_B</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">        <span class="keyword">return</span> MyFunc_A();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">        MyFunc_B();</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><img src="https://raw.githubusercontent.com/gatieme/AderXCoding/master/language/c/backtrace/builtin.png" alt="运行结果"></p>
<h2 id="4-参考资料"><a href="#4-参考资料" class="headerlink" title="#4    参考资料"></a>#4    参考资料</h2><p><a href="https://www.douban.com/group/topic/54568167/" target="_blank" rel="noopener">Stack backtrace 的实现</a></p>
<p><a href="http://en.verysource.com/code/6087935_1/backtrace.c.html" target="_blank" rel="noopener">backtrace.c：Code Content</a></p>
<p><a href="https://www.xuebuyuan.com/2867142.html" target="_blank" rel="noopener">一个glibc中abort不能backtrace的问题</a></p>
<p><a href="https://blog.csdn.net/jxgz_leo/article/details/53458366" target="_blank" rel="noopener">在Linux中如何利用backtrace信息解决问题</a></p>
<p><a href="https://blog.csdn.net/jasonchen_gbd/article/details/44066815?utm_source=blogxgwz8" target="_blank" rel="noopener">内核中dump_stack()的实现，并在用户态模拟dump_stack()</a></p>
<p><br></p>
<ul>
<li><p>本作品/博文 ( <a href="http://blog.csdn.net/gatieme" target="_blank" rel="noopener">AderStep-紫夜阑珊-青伶巷草 Copyright ©2013-2017</a> ), 由 <a href="http://blog.csdn.net/gatieme" target="_blank" rel="noopener">成坚(gatieme)</a> 创作.</p>
</li>
<li><p>采用<a rel="noopener" href="http://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank"><img alt="知识共享许可协议" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png"></a><a rel="noopener" href="http://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议</a>进行许可. 欢迎转载、使用、重新发布, 但务必保留文章署名<a href="http://blog.csdn.net/gatieme" target="_blank" rel="noopener">成坚gatieme</a> ( 包含链接: <a href="http://blog.csdn.net/gatieme" target="_blank" rel="noopener">http://blog.csdn.net/gatieme</a> ), 不得用于商业目的.</p>
</li>
<li><p>基于本文修改后的作品务必以相同的许可发布. 如有任何疑问，请与我联系.</p>
</li>
</ul>

    </div>
    <p class="eof">-- EOF --</p>
    <p class="post-meta">
        <span class="post-cat">分类：
            <a class="cat-link" href="/categories/编程珠玑/">编程珠玑</a>
        </span>
        <span class="post-tags">
            标签：
            
    
        <a href="/tags/linux/" title="linux">linux</a> / 
    
        <a href="/tags/debug/" title="debug">debug</a>
    

        </span>
    </p>
</article>
<!-- 分享按钮 -->

  <div class="article-share clearfix text-center">
    <div class="share-area">
      <span class="share-txt">分享到：</span>
      <a href="javascript: window.open('http://service.weibo.com/share/share.php?url=' + encodeURIComponent(location.href) + '&title=' + document.title + '&language=zh_cn');" class="share-icon weibo"></a>
      <a href="javascript: alert('请复制链接到微信并发送');" class="share-icon wechat"></a>
      <a href="javascript: window.open('http://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url=' + encodeURIComponent(location.href) + '&title=' + document.title);" class="share-icon qqzone"></a>
      <a href="javascript: window.open('http://connect.qq.com/widget/shareqq/index.html?url=' + encodeURIComponent(location.href) + '&desc=Gatieme个人博客&title=' + document.title + '&callback=' + encodeURIComponent(location.href));" class="share-icon qq"></a>
      <a href="javascript: window.open('http://shuo.douban.com/!service/share?href=' + encodeURIComponent(location.href) + '&name=' + document.title + '&text=' + document.title);" class="share-icon douban"></a>
    </div>
  </div>



<!-- 上一篇/下一篇 -->

<div class="article-nav clearfix">
    
    <span class="prev fl">
        上一篇<br>
        <a href="/2020/05/24/2020/0524-0001-linux_cfs_scheduler_31_wake_affine/">
            
                Linux CFS调度器之唤醒WAKE_AFFINE 机制--Linux进程的管理与调度(三十一)
            
        </a>
    </span>
    

    
    <span class="next fr">
        下一篇<br>
        <a href="/2018/09/30/2018/0930-0003-qemu_use_9pnet_virtio_fs_to_share_folder/">
            
                qemu中使用 9p virtio, 支持 host 和 guest 中共享目录
            
        </a>
    </span>
    
</div>

<!-- 文章评论 -->

  <script src="/js/comment.js?v=1615735432648"></script>
  <div id="comments" class="comment">
    <!--
    <div class="sign-bar">
      GitHub 已登录!
      <span class="sign-link">登出</span>
    </div>
    <section class="box">
      <div class="com-avatar"><img src="/img/gatieme.jpg" alt="avatar"></div>
      <div class="com-text">
        <div class="main">
          <textarea class="text-area-edited show" placeholder="欢迎评论！"></textarea>
          <div class="text-area-preview"></div>
        </div>
        <div class="switch">
          <div class="switch-item on">编辑</div>
          <div class="switch-item">预览</div>
        </div>
        <div class="button">提交</div>
      </div>
    </section>
    <section class="tips">注：评论支持 markdown 语法！</section>
    <section class="list-wrap">
      <ul class="list">
        <li>
          <div class="user-avatar">
            <a href="/">
              <img src="/img/gatieme.jpg" alt="user-avatar">
            </a>
          </div>
          <div class="user-comment">
            <div class="user-comment-header">
              <span class="post-name">张德龙</span>
              <span class="post-time">2017年12月12日</span>
              <span class="like liked">已赞</span>
              <span class="like-num">2</span>
            </div>
            <div class="user-comment-body">333333</div>
          </div>
        </li>
        <li>
          <div class="user-avatar">
            <a href="/">
              <img src="/img/gatieme.jpg" alt="user-avatar">
            </a>
          </div>
          <div class="user-comment">
            <div class="user-comment-header">
              <span class="post-name">刘德华</span>
              <span class="post-time">2017年12月12日</span>
              <span class="like">点赞</span>
              <span class="like-num">2</span>
            </div>
            <div class="user-comment-body">vvvvv</div>
          </div>
        </li>
      </ul>
      <div class="page-nav">
        <a href="javascript: void(0);" class="item">1</a>
        <a href="javascript: void(0);" class="item">2</a>
        <a href="javascript: void(0);" class="item current">3</a>
      </div>
    </section>
    -->
  </div>
  <script>
  JELON.Comment({
    container: 'comments',
    label: '2018/1117-0001-use_glibc_backtrace_to_report_active_stack_frames_userspace' || '2018/11/17/2018/1117-0001-use_glibc_backtrace_to_report_active_stack_frames_userspace/',
    owner: 'gatieme',
    repo: 'blog_comments',
    clientId: 'cf796c25fcf4369b9295',
    clientSecret: 'c2ecfa50b9914a8fc9655ede7c9e6cf2ff84a70c'
  });
  </script>




            </div>
        </section>
        <!-- 侧栏部分 -->
<aside class="sidebar">
    
    <section class="widget">
        <h3 class="widget-hd"><strong>文章搜索</strong></h3>
        <div class="search-form">
  <form id="searchForm" method="GET" action="https://www.google.com/search" ectype="application/x-www-form-urlencoded" target="_blank" autocomplete="false" onsubmit="javascript: return false;">
    <input id="searchKeyword" type="text" class="form-control" placeholder="输入关键字搜索" autocomplete="false">
    <input id="searchKeywordHidden" type="hidden" name="q">
    <input id="searchButton" class="btn" type="submit" value="搜索">
  </form>
</div>

    </section>
    

    <section class="widget">
        <h3 class="widget-hd"><strong>文章分类</strong></h3>
        <!-- 文章分类 -->
<ul class="widget-bd">
    
    <li>
        <a href="/categories/linux/">linux</a>
        <span class="badge">(0)</span>
    </li>
    
    <li>
        <a href="/categories/hexo/">hexo</a>
        <span class="badge">(0)</span>
    </li>
    
    <li>
        <a href="/categories/qemu/">qemu</a>
        <span class="badge">(0)</span>
    </li>
    
    <li>
        <a href="/categories/debug/">debug</a>
        <span class="badge">(0)</span>
    </li>
    
    <li>
        <a href="/categories/编程珠玑/">编程珠玑</a>
        <span class="badge">(7)</span>
    </li>
    
    <li>
        <a href="/categories/技术积累/">技术积累</a>
        <span class="badge">(3)</span>
    </li>
    
    <li>
        <a href="/categories/内核探秘/">内核探秘</a>
        <span class="badge">(3)</span>
    </li>
    
</ul>
    </section>

    
    <section class="widget">
        <h3 class="widget-hd"><strong>热门标签</strong></h3>
        <!-- 文章标签 -->
<div class="widget-bd tag-wrap">
  
    <a class="tag-item" href="/tags/linux/" title="linux">linux (10)</a>
  
    <a class="tag-item" href="/tags/debug/" title="debug">debug (6)</a>
  
    <a class="tag-item" href="/tags/tools/" title="tools">tools (4)</a>
  
    <a class="tag-item" href="/tags/scheduler/" title="scheduler">scheduler (3)</a>
  
    <a class="tag-item" href="/tags/hexo/" title="hexo">hexo (2)</a>
  
    <a class="tag-item" href="/tags/blog/" title="blog">blog (2)</a>
  
    <a class="tag-item" href="/tags/qemu/" title="qemu">qemu (1)</a>
  
    <a class="tag-item" href="/tags/topdown/" title="topdown">topdown (1)</a>
  
    <a class="tag-item" href="/tags/kernel/" title="kernel">kernel (1)</a>
  
</div>
    </section>
    

    

    
    <!-- 友情链接 -->
    <section class="widget">
        <h3 class="widget-hd"><strong>友情链接</strong></h3>
        <!-- 文章分类 -->
<ul class="widget-bd">
    
        <li>
            <a href="https://blog.csdn.net/gatieme" target="_blank" title="我的 CSDN 博客">CSDN--紫夜阑珊-青伶巷草</a>
        </li>
    
        <li>
            <a href="https://xydh.fun/gatieme" target="_blank" title="我的炫猿导航主页">炫猿导航</a>
        </li>
    
        <li>
            <a href="https://jelon.info" target="_blank" title="Jelon 的博客">Jelon 的博客</a>
        </li>
    
</ul>
    </section>
    
</aside>
<!-- / 侧栏部分 -->
    </div>

    <!-- 博客底部 -->
    <footer class="footer">
    &copy;
    
        2014-2021
    

    <a href="/">紫夜阑珊-青伶巷草</a>
</footer>
<div class="back-to-top" id="JELON__backToTop" title="返回顶部">返回顶部</div>

    <!--博客js脚本 -->
    <!-- 这里放网站js脚本 -->
<script src="/js/main.js?v=1615735433180"></script>

</body>
</html>
